package com.jt.www.biz.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.jt.www.biz.pay.service.PayOutService;
import com.jt.www.dao.mapper.woxuebao.PayOutEntityMapper;
import com.jt.www.domain.enums.wxb.PayOutSetEnum;
import com.jt.www.enums.issue.AppStatusEnum;
import com.jt.www.enums.issue.FinanceStatusEnum;
import com.jt.www.enums.woxuebao.PayOutStatusEnum;
import com.jt.www.model.pay.StatusRecordVO;
import com.jt.www.model.remote.ins.InsManagerResultVO;
import com.jt.www.model.reps.ResponseData;
import com.jt.www.model.vo.InsManagerQo;
import com.jt.www.model.woxuebao.PayOutEntity;
import com.jt.www.remote.ins.InsClient;
import com.jt.www.util.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * Created by shaoyn on 2020/02/19.
 */
@Service
public class PayOutServiceImpl implements PayOutService {

    public static final Logger log = LoggerFactory.getLogger(PayOutServiceImpl.class);
    @Autowired
    private InsClient insClient;
    @Autowired
    private PayOutEntityMapper payOutEntityMapper;

    /**
     * 保存支付过期逻辑
     *
     * @param payOutEntity
     */
    public Date savePayOut(PayOutEntity payOutEntity){

        String[] appCodes = payOutEntity.getApplicationFormCode().split(",");

        Long outTimes = PayOutSetEnum.getPayTimeByProductCode(payOutEntity.getProductCode(), payOutEntity.getIsRenewal());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date createTime;
        if(null != payOutEntity.getCreateTime()){
            createTime = payOutEntity.getCreateTime();
        } else {
            createTime = new Date();
            payOutEntity.setCreateTime(createTime);
        }
        log.info("投保时间：" + sdf.format(createTime));

        Date payOutTime = new Date(createTime.getTime() + outTimes);
        log.info("支付超时时间：" + sdf.format(payOutTime));

        //如果不是倒签单， 并且 支付超时时间>起保时间 那么支付超时时间 = 起保时间，否则 支付超时时间 = 当前时间 + 配置时间
        if (!isBackIssue(payOutEntity.getStartTime())
                && DateUtils.compareDate(payOutTime, payOutEntity.getStartTime())) {
            payOutTime = payOutEntity.getStartTime();
        }

        payOutEntity.setPayOutTime(payOutTime);
        payOutEntity.setStatus(PayOutStatusEnum.DEFAULT.getCode());

        for(String appCode : appCodes){
            //如果该投保单已经存在超时时间记录，则更新
            PayOutEntity payOut = selectByAppCode(appCode);
            payOutEntity.setApplicationFormCode(appCode);
            if(null == payOut){
                payOutEntity.setId(null);
                payOutEntityMapper.insertSelective(payOutEntity);
            } else {
                payOutEntity.setId(payOut.getId());
                payOutEntityMapper.updateByPrimaryKeySelective(payOutEntity);
                continue;
            }
        }
        return payOutTime;
    }


    @Override
    public PayOutEntity selectByAppCode(String appCode){
        PayOutEntity payOutEntity = new PayOutEntity();
        payOutEntity.setApplicationFormCode(appCode);
        List<PayOutEntity> payOutEntities = payOutEntityMapper.select(payOutEntity);

        if(!CollectionUtils.isEmpty(payOutEntities)){
            return payOutEntities.get(0);
        }
        return null;
    }

    /**
     * 通过起保时间判断是否倒签单
     * @param startTime
     * @return true 是倒签单
     * @return false 不是倒签单
     */
    private boolean isBackIssue(Date startTime){
        return DateUtils.compareDate(new Date(), startTime);
    }

    /**
     * 得到需要校验是否支付超时的集合
     * 返回超时时间大于当前 等于 当前 时间的记录
     * @return
     */
    public List<PayOutEntity> getNeedVerifyList(){

        Weekend<PayOutEntity> weekend = new Weekend<>(PayOutEntity.class);
        WeekendCriteria<PayOutEntity, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(PayOutEntity::getStatus, PayOutStatusEnum.DEFAULT.getCode());
        criteria.andLessThan(PayOutEntity::getPayOutTime, new Date());
        return payOutEntityMapper.selectByExample(weekend);
    }

    /**
     * 处理支付状态
     * @param payOutEntities
     * @return
     */
    public void processPayOut(List<PayOutEntity> payOutEntities){
        if(CollectionUtils.isEmpty(payOutEntities)){
            return ;
        }
        for (PayOutEntity payOutEntity : payOutEntities) {

            String findCode = "ProcessPayOut_" + payOutEntity.getApplicationFormCode();
            InsManagerQo insManagerQo = new InsManagerQo();
            insManagerQo.setChannelCode("edu");
            insManagerQo.setChannelType("02");
            insManagerQo.setAppCode(payOutEntity.getApplicationFormCode());
            try {
                ResponseData rets = insClient.searchManagerAppList(JSON.toJSONString(insManagerQo));
                log.info("{} 支付超时, 查询投保中心详情：{}", findCode, JSON.toJSONString(rets));
                //投保中心没有该投保单号
                if (null == rets || null == rets.getList() || rets.getList().size() == 0) {
                    log.info("{} 支付超时, 无投保单详情，修改支付状态为投保单错误", findCode);
                    updatePayStatusById(payOutEntity.getId(), PayOutStatusEnum.WRONG);
                } else {
                    //投保中心返回的结果集
                    List<InsManagerResultVO> list = (List<InsManagerResultVO>) rets.getList();
                    list = JSON.parseArray(JSON.toJSONString(list), InsManagerResultVO.class);
                    InsManagerResultVO insManagerResultVO = list.get(0);

                    //添加修改状态的集合
                    StatusRecordVO statusRecordVO = new StatusRecordVO();
                    statusRecordVO.setApplicationFormCode(insManagerResultVO.getAppCode());
                    statusRecordVO.setOperator("edu_system");// 当前用户
                    statusRecordVO.setTapplicationFormId(0);
                    statusRecordVO.setType("00");

                    //已支付
                    if (FinanceStatusEnum.FS_01.getCode().equals(insManagerResultVO.getFinanceStatus())) {

                        log.info("{} 支付超时, 投保单支付状态为已支付，同步修改支付状态为支付成功", findCode);
                        updatePayStatusById(payOutEntity.getId(), PayOutStatusEnum.SUCCESS);
                        //如果之前已经将该投保单设置成了已失效状态，在这里将状态修正过来
                        if (AppStatusEnum.AS_11.getCode().equals(insManagerResultVO.getAppStatus())) {
                            //如果已出单修改为已出单，如果未出单修改成待出单
                            if(StringUtils.isNotBlank(insManagerResultVO.getInsurancePolicyNo())){
                                statusRecordVO.setNewStatus(AppStatusEnum.AS_10.getCode());
                            } else {
                                statusRecordVO.setNewStatus(AppStatusEnum.AS_08.getCode());
                            }
                            insClient.updateApplicationStatus(Lists.newArrayList(statusRecordVO));
                        }
                    } else {
                        //修改成已取消状态
                        statusRecordVO.setNewStatus(AppStatusEnum.AS_11.getCode());
                        insClient.updateApplicationStatus(Lists.newArrayList(statusRecordVO));
                        //修改本地库
                        log.info("{} 支付超时, 投保单支付状态不为已支付，同步修改支付状态为支付超时", findCode);
                        updatePayStatusById(payOutEntity.getId(), PayOutStatusEnum.PAY_OUT);
                    }
                }

            } catch (Exception e) {
                log.info("{}投保中心调用支付校验接口异常", findCode);
                throw new RuntimeException(e.getMessage());
            }
        }
    }

    @Override
    public void updatePayStatus(String appCode, PayOutStatusEnum payOutStatusEnum) {
        Weekend<PayOutEntity> weekend = Weekend.of(PayOutEntity.class);
        WeekendCriteria<PayOutEntity, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(PayOutEntity::getApplicationFormCode, appCode);

        PayOutEntity payOutEntity = new PayOutEntity();
        payOutEntity.setStatus(payOutStatusEnum.getCode());
        payOutEntityMapper.updateByExampleSelective(payOutEntity, weekend);
    }

    private void updatePayStatusById(Long id, PayOutStatusEnum payOutStatusEnum) {
        PayOutEntity payOutEntity = new PayOutEntity();
        payOutEntity.setId(id);
        payOutEntity.setStatus(payOutStatusEnum.getCode());
        payOutEntityMapper.updateByPrimaryKeySelective(payOutEntity);
    }


}
